package com.free.bsf.file.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.free.bsf.file.FileException;
import com.free.bsf.file.base.StsToken;
import com.free.bsf.file.base.UploadToken;
import com.free.bsf.file.config.AliOssProperties;
import com.qiniu.common.QiniuException;
import com.qiniu.util.StringUtils;
import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.fastjson.JSONObject;

/**
 * @description:
 * @Author YH
 * @Date 2021/12/3 17:47
 */
public class AliOssFileProvider extends AbstractFileProvider {

    protected OSS ossClient;
    protected IAcsClient iAcsClient;
    protected String region;
    protected String roleArn;
    protected String roleSessionName;
    protected String endpoint;
    protected String accessKeyId;
    protected String accessKeySecret;
    protected String bucketName;
    protected String path;
    protected String timeOut;

    public AliOssFileProvider(AliOssProperties properties) {
        if (StringUtils.isNullOrEmpty(properties.getAccessKeyId())) {
            throw new FileException("阿里oss文件服务缺少AccessKeyId配置");
        }
        if (StringUtils.isNullOrEmpty(properties.getAccessKeySecret())) {
            throw new FileException("阿里oss文件服务缺少AccessKeySecret配置");
        }
        if (StringUtils.isNullOrEmpty(properties.getEndpoint())) {
            throw new FileException("阿里oss文件服务缺少Endpoint配置");
        }
        if (StringUtils.isNullOrEmpty(properties.getBucketName())) {
            throw new FileException("阿里oss文件服务缺少BucketName配置");
        }
        if (StringUtils.isNullOrEmpty(properties.getRegion())) {
            throw new FileException("阿里oss文件服务缺少Region配置");
        }
        if (StringUtils.isNullOrEmpty(properties.getRoleArn())) {
            throw new FileException("阿里oss文件服务缺少RoleArn配置");
        }
        if (StringUtils.isNullOrEmpty(properties.getRoleSessionName())) {
            throw new FileException("阿里oss文件服务缺少RoleSessionName配置");
        }
        path = properties.getTempDir();
        //路径初始化
        if (StringUtils.isNullOrEmpty(path)) {
            path = "tmp/";
        }
        this.accessKeyId = properties.getAccessKeyId();
        this.accessKeySecret = properties.getAccessKeySecret();
        //oss-cn-hangzhou.aliyuncs.com
        this.endpoint = properties.getEndpoint();
        //桶名称
        this.bucketName = properties.getBucketName();
        //cn-hangzhou
        this.region = properties.getRegion();
        //RAM角色的ARN acs:ram::1069735822596087:role/oss-file
        this.roleArn = properties.getRoleArn();
        //扮演临时角色名称 自定义
        this.roleSessionName = properties.getRoleSessionName();
        this.timeOut = properties.getTimeOut();
        //初始化STS客户端
        DefaultProfile profile = DefaultProfile.getProfile(region, accessKeyId, accessKeySecret);
        //STS 客户端初始化
        this.iAcsClient = new DefaultAcsClient(profile);
        //OSS 客户端初始化
        this.ossClient = new OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret);
    }

    @Override
    public String uploadSTS(InputStream input, String name, String jsonStsToken) {
        OSS ossClient = null;
        try {
            StsToken stsToken = JSONObject.toJavaObject(JSONObject.parseObject(jsonStsToken),StsToken.class);
            //每次请求上传要获取临时用户 AccessKeySecret 和 AccessKeyId 不固定
            ossClient = new OSSClientBuilder()
                    .build(endpoint, stsToken.getAccessKeyId(),
                            stsToken.getAccessKeySecret(),
                            stsToken.getSecurityToken());
            String filePath = createFileKey(path, name);
            //需求配置oss上传回调
            ossClient.putObject(bucketName, filePath, input);
            return "https://" + bucketName + "." + endpoint + "/" + filePath;
        } catch (OSSException e) {
            throw new FileException("阿里OSS上传文件服务", e);
        } catch (Exception e) {
            throw new FileException("阿里OSS上传文件服务", e);
        } finally {
            ossClient.shutdown();
        }
    }

    @Override
    public String uploadSTS(String filePath, String path, String name, String jsonStsToken) {
        OSS ossClient = null;
        try {
            StsToken stsToken = JSONObject.toJavaObject(JSONObject.parseObject(jsonStsToken),StsToken.class);
            //每次请求上传要获取临时用户 AccessKeySecret 和 AccessKeyId 不固定
            ossClient = new OSSClientBuilder()
                    .build(endpoint, stsToken.getAccessKeyId(),
                            stsToken.getAccessKeySecret(),
                            stsToken.getSecurityToken());
            String fileOssPath = createFileKey(path, name);
            ossClient.putObject(bucketName, fileOssPath, new File(filePath));
            return "https://" + bucketName + "." + endpoint + "/" + fileOssPath;
        } catch (OSSException e) {
            throw new FileException("阿里OSS上传文件服务", e);
        } catch (Exception e) {
            throw new FileException("阿里OSS上传文件服务", e);
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 阿里云OSS文件上传 非STS
     * @param input
     * @param name
     * @return
     */
    @Override
    public String upload(InputStream input, String path, String name) {
        try {
            //上传至默认地址
            String filePath = createFileKey(path, name);
            ossClient.putObject(bucketName,filePath,input);
            return "https://" + bucketName + "." + endpoint + "/" + filePath;
        } catch (OSSException e) {
            throw new FileException("阿里OSS上传文件服务", e);
        } catch (Exception e) {
            throw new FileException("阿里OSS上传文件服务", e);
        }
    }

    @Override
    public String upload(String filePath, String path, String name) {
        try {
            ossClient.putObject(bucketName, createFileKey(path, name), new File(filePath));
            return "https://" + bucketName + "." + endpoint + "/" + filePath;
        }catch (OSSException e) {
            throw new FileException("阿里OSS上传文件服务", e);
        } catch (Exception e) {
            throw new FileException("阿里OSS上传文件服务", e);
        }
    }
    /**
     * 获取临时角色的token和accessKeyId accessKeySecret
     *
     * @return
     */
    @Override
    public Map<String,String> uploadToken(String name) {
        Map<String,String> map = new ConcurrentHashMap();
        AssumeRoleRequest request = new AssumeRoleRequest();
        request.setRegionId(region);
        request.setRoleArn(roleArn);
        request.setRoleSessionName(roleSessionName);
        try {
            if (!StringUtils.isNullOrEmpty(timeOut)){
                //设置超时时间 单位:分
                request.setDurationSeconds(Integer.parseInt(timeOut) * 60L);
            }
            AssumeRoleResponse response = iAcsClient.getAcsResponse(request);
            AssumeRoleResponse.Credentials credentials = response.getCredentials();
            //将STS返回的临时accessKeyId和accessKeySecret填入
            StsToken stsToken = new StsToken();
            stsToken.setSecurityToken(credentials.getSecurityToken());
            stsToken.setAccessKeyId(credentials.getAccessKeyId());
            stsToken.setAccessKeySecret(credentials.getAccessKeySecret());
            map.put("token",JSONObject.toJSONString(stsToken));
            return map;
        } catch (ClientException e) {
            throw new FileException("阿里OSS获取STS信息异常", e);
        } catch (NumberFormatException e){
            throw new FileException("请入正确STS临时用户超时时间",e);
        }catch (Exception e) {
            throw new FileException("阿里OSS获取STS信息异常", e);
        }
    }

    /**
     * 阿里云OSS单文件删除
     * @param url
     * @return
     */
    @Override
    public boolean delete(String url) {
        String path;
        try {
            path = new URL(url).getPath();
            if (path.startsWith("/")) {
                path = path.substring(1);
            }
        } catch (MalformedURLException e) {
            throw new FileException("URL错误：" + url, e);
        }
        try {
            ossClient.deleteObject(bucketName, path);
            return true;
        } catch (OSSException e) {
            return false;
        }
    }

    @Override
    public String info() {
        return "阿里OSS云文件服务:" + com.free.bsf.core.util.StringUtils.nullToEmpty(endpoint);
    }

}
